package org.beyondhc.lessons.observer;

import java.util.logging.Logger;

import junit.framework.TestCase;

import org.beyondhc.test.LogMsgCaptor;
import org.junit.Test;

/**
 * 
 * Shows how to prepare for the possible future need of observer pattern.
 * 
 * @author Jaana Kulmala
 * 
 */
public class DegeneratedObserver extends TestCase {

    public class Koala {
        private KoalaObserver keeper;

        public void setHungry(final boolean isHungry) {
            if (keeper != null) {
                keeper.koalaUpdate(this, isHungry);
            }
        }

        public void setObserver(final KoalaObserver keeper) {
            this.keeper = keeper;
        }

        @Override
        public String toString() {
            return "koala";
        }
    }

    public interface KoalaObserver {
        void koalaUpdate(Koala koala, boolean isHungry);
    }

    public class WaterPipe {
        private WaterPipeObserver observer;

        public void setBroken(final boolean isBroken) {
            if (observer != null) {
                observer.pipeFixingNeeded();
            }
        }

        public void setObserver(final WaterPipeObserver observer) {
            this.observer = observer;
        }

    }

    public interface WaterPipeObserver {

        void pipeFixingNeeded();

    }

    public class ZooKeeper implements KoalaObserver, WaterPipeObserver {

        @Override
        public void koalaUpdate(final Koala koala, final boolean isHungry) {
            if (isHungry) {
                LOGGER.info("Oh, the "
                        + koala
                        + " is hungry. I'll go into the cage and give some eucalyptus to the little fella!");
            }
        }

        @Override
        public void pipeFixingNeeded() {
            LOGGER.info("Gonna fix the pipe now!");
        }
    }

    private static final transient Logger LOGGER = Logger
            .getLogger(DegeneratedObserver.class.getName());

    /**
     * Here is the degenerated observer in action.
     */
    @Test
    public void testKoalaGetsFood() {
        final LogMsgCaptor logMsgCaptor = new LogMsgCaptor(LOGGER);
        final Koala koala = new Koala();
        final ZooKeeper zooKeeper = new ZooKeeper();

        koala.setObserver(zooKeeper);
        koala.setHungry(true);
        assertEquals(
                "The koala should get food",
                "Oh, the koala is hungry. I'll go into the cage and give some eucalyptus to the little fella!",
                logMsgCaptor.getMsg());
    }

    /**
     * And the code keeps clean even when other stuff is added with the same
     * idea.
     */
    @Test
    public void testPipeGetsFixed() {
        final LogMsgCaptor logMsgCaptor = new LogMsgCaptor(LOGGER);
        final ZooKeeper zooKeeper = new ZooKeeper();
        final WaterPipe pipe = new WaterPipe();
        pipe.setObserver(zooKeeper);
        pipe.setBroken(true);
        final String latestMsg = logMsgCaptor.getMsg();
        assertEquals("The zookeeper should notice the broken pipe",
                "Gonna fix the pipe now!", latestMsg);
    }

}
